pub mod http;
pub mod process;

use std::{collections::VecDeque, sync::LazyLock};

use crate::{
    error::*,
    http::{base::parse::HttpResult, proxy::HttpProxy},
};
use async_trait::async_trait;
use bytes::Bytes;
use http::example::HttpExample;
use process::example::Example;

#[allow(dead_code)]
#[async_trait]
pub trait ProcessModule: Sync + Send {
    fn get_name(&self) -> &str;

    async fn init_process_handle(&self) -> Result<()>;
    async fn exit_process_handle(&self) -> Result<()>;
}

#[allow(dead_code)]
#[async_trait]
pub trait HttpAccessHandle: Sync + Send {
    fn get_name(&self) -> &str;
    async fn access_handle(&self, proxy: &mut HttpProxy) -> Result<()>;
}

#[allow(dead_code)]
#[async_trait]
pub trait HttpHeaderFilterHandle: Sync + Send {
    fn get_name(&self) -> &str;
    fn set_next(&self, next: &'static dyn HttpHeaderFilterHandle);
    async fn header_filter(&self, proxy: &mut HttpProxy) -> Result<()>;
}

#[allow(dead_code)]
#[async_trait]
pub trait HttpBodyFilterHandle: Sync + Send {
    fn get_name(&self) -> &str;
    fn set_next(&self, next: &'static dyn HttpBodyFilterHandle);
    async fn body_filter(
        &self,
        proxy: &mut HttpProxy,
        bufs: &mut VecDeque<Bytes>,
        done: bool,
    ) -> Result<HttpResult>;
}

pub struct HttpFinalFilter {}

#[async_trait]
impl HttpHeaderFilterHandle for HttpFinalFilter {
    fn get_name(&self) -> &str {
        "header_final_filter"
    }

    fn set_next(&self, next: &'static dyn HttpHeaderFilterHandle) {
        _ = next;
        panic!("it's latest header filter");
    }

    async fn header_filter(&self, proxy: &mut HttpProxy) -> Result<()> {
        proxy.header_final_filter().await
    }
}

#[async_trait]
impl HttpBodyFilterHandle for HttpFinalFilter {
    fn get_name(&self) -> &str {
        "header_final_filter"
    }

    fn set_next(&self, next: &'static dyn HttpBodyFilterHandle) {
        _ = next;
        panic!("it's latest header filter");
    }

    async fn body_filter(
        &self,
        proxy: &mut HttpProxy,
        bufs: &mut VecDeque<Bytes>,
        done: bool,
    ) -> Result<HttpResult> {
        proxy.body_final_filter(bufs, done).await
    }
}

impl HttpFinalFilter {
    pub fn new() -> Self {
        HttpFinalFilter {}
    }
}

#[allow(dead_code)]
pub struct ModuleMgr {
    process_modules: Vec<&'static dyn ProcessModule>,
    http_access_handles: Vec<&'static dyn HttpAccessHandle>,
    http_header_filter: &'static dyn HttpHeaderFilterHandle,
    http_body_filter: &'static dyn HttpBodyFilterHandle,
}

#[allow(dead_code)]
impl ModuleMgr {
    pub fn get_instance() -> &'static ModuleMgr {
        static MODULE_MGR: LazyLock<ModuleMgr> = LazyLock::new(ModuleMgr::new);

        &MODULE_MGR
    }

    pub async fn init_process_handles() -> Result<()> {
        let mgr = ModuleMgr::get_instance();
        for v in mgr.process_modules.iter() {
            v.init_process_handle().await.if_err(
                ErrorType::ProcessHandleFailed,
                format!("process {} init_main_handle failed", v.get_name()),
            )?;
        }

        Ok(())
    }

    pub async fn exit_process_handles() -> Result<()> {
        let mgr = ModuleMgr::get_instance();
        for v in mgr.process_modules.iter() {
            v.exit_process_handle().await.if_err(
                ErrorType::ProcessHandleFailed,
                format!("process {} exit_proccess_handle failed", v.get_name()),
            )?;
        }

        Ok(())
    }

    pub async fn http_access_handles(proxy: &mut HttpProxy) -> Result<()> {
        let mgr = ModuleMgr::get_instance();
        for v in mgr.http_access_handles.iter() {
            v.access_handle(proxy).await.if_err(
                ErrorType::ProcessHandleFailed,
                format!("process {} http access handle failed", v.get_name()),
            )?;

            if proxy.exit_status != 0 {
                return Ok(());
            }
        }

        Ok(())
    }

    pub async fn process_http_header_filter(
        proxy: &mut HttpProxy,
    ) -> Result<()> {
        let mgr = ModuleMgr::get_instance();
        mgr.http_header_filter.header_filter(proxy).await
    }

    pub async fn process_http_body_filter(
        proxy: &mut HttpProxy,
        bufs: &mut VecDeque<Bytes>,
        done: bool,
    ) -> Result<HttpResult> {
        let mgr = ModuleMgr::get_instance();
        mgr.http_body_filter.body_filter(proxy, bufs, done).await
    }

    pub fn register_process_module(&mut self, m: &'static dyn ProcessModule) {
        self.process_modules.push(m);
    }

    pub fn register_http_access_handle(
        &mut self,
        h: &'static dyn HttpAccessHandle,
    ) {
        self.http_access_handles.push(h);
    }

    pub fn register_http_header_filter(
        &mut self,
        filter: &'static dyn HttpHeaderFilterHandle,
    ) {
        filter.set_next(self.http_header_filter);
        self.http_header_filter = filter;
    }

    pub fn register_http_body_filter(
        &mut self,
        filter: &'static dyn HttpBodyFilterHandle,
    ) {
        filter.set_next(self.http_body_filter);
        self.http_body_filter = filter;
    }

    fn new() -> Self {
        let http_final_filter = Box::new(HttpFinalFilter::new());
        let leak_http_final_filter = Box::leak(http_final_filter);

        let mut mgr = ModuleMgr {
            process_modules: Vec::new(),
            http_access_handles: Vec::new(),
            http_header_filter: leak_http_final_filter,
            http_body_filter: leak_http_final_filter,
        };

        let example = Box::new(Example::new());
        let leak_example = Box::leak(example);
        mgr.register_process_module(leak_example);

        let http_example = Box::new(HttpExample::new());
        let leak_http_example = Box::leak(http_example);

        mgr.register_http_header_filter(leak_http_example);
        mgr.register_http_body_filter(leak_http_example);

        mgr
    }
}
